import json
import time
import os.path
import pickle
import os
# python---IO操作
# 1、python的IO操作主要指的是什么？
# 输入----就是将一个持久化设备中的内容读取到内存
# 输出----就是将内存中的数据保存在一个持久化设备上
# 注意：持久化设备指的是：ROM----断电后数据不会消失、内存：RAM—断电后数据消失

# 2、IO操作的整个过程
#       打开文件–>读取数据–>数据运算–>输出数据–>关闭资源
# 3、IO的分类
# 根据数据类型我们将IO操作分为两大类
# 字符流：操作的对象是字符串、文本文档
# 字节流：操作的对象是字节数据，比如图片、视频等
# 根据数据的流向分流
# 输入流、输出流
# 4、IO模块提供的方法
# open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
# 参数解释：
# file：以字符串来指定需要打开的文件路径和名称
# model: 以字符串指定打开文件的存取方式
# r----读取模式（默认值）
# w----写入模式，创建新文件或覆盖旧文件
# a----追加写入，创建新文件或追加于旧文件的末尾
# x----写入模式，若文件不存在，则新创建文件，文件存在则有错误
# t----文本模式，（默认值）
# b----二进制模式
# r±—更新模式，可读可写，文件需从在，从文件开头进行读写
# w±—更新模式，可读可写，创建新文件或追加旧文件，从文件开头进行读写
# a±—更新模式，可读可写，创建新文件或从旧文件的尾部进行读写
# buffering 设置缓冲区大小，默认值为-1。若为0，表示关闭缓冲区，要以二进制进行处理。若为1，表示以文字进行处理。若大于1，表示为缓冲区的固定大小，通常缓冲区的容量为4096或8192字节
# encoding 打开文件时一般所采用的文字编码，默认值为none
# errors 错误处理原则，不能以二进制来处理，默认值为none
# newline 换行操作
# closefd 文件描述字符，表示关闭文件时是否也关闭文件描述，默认值为Ture
# opener 负责打开文件描述，默认值为none

# 5、字符操作
# 从磁盘读取到内存中（输入）
fr = open('C:\\Users\\vainuer\\Desktop\\Test\\test.txt',
          'rt', encoding='utf-8')
print(fr.read())
fr.close()
# 将内存中的数据保存在磁盘中(输出)
message = '将内存中的数据保存在磁盘中(输出)'
fw = open(r'C:\Users\vainuer\Desktop\Test\test1.txt', 'wt', encoding='utf-8')
fw.write(message)
fw.close
# 6、字节操作
# 将磁盘中的图片读取到内存中（输入）
fr = open('C:/Users/vainuer/Desktop/Test/test1.jpg', 'rb')
image = fr.read()
# 将内存中的图片保存在磁盘中(输出)
fw = open(r'C:\Users\vainuer\Desktop\Test\test2.jpg', 'wb')
fw.write(image)
fr.close()
fw.close()

# 7、with语句
with open(r'C:\Users\vainuer\Desktop\Test\test1.txt', 'rt', encoding='utf-8') as f:
    print(f.read())
os.remove(r'C:\Users\vainuer\Desktop\Test\test1.txt')

# 8、对象序列化和反序列化
# 序列化：（dumps）对象序列化成字节数据存储在磁盘。dump：序列化并保存在文件中
f = open(r'C:\Users\vainuer\Desktop\Test\test1.txt', 'wb')
data = {'key1': 'value1', 'key2': 'value2'}
f.write(pickle.dumps(data))
f.close()
# 反序列化：（loads）将序列化的字节数据反序列化成对象。load：将序列化字符串从文件读取并反序列化
f = open(r'C:\Users\vainuer\Desktop\Test\test1.txt', 'rb')
data = pickle.loads(f.read())
print(data)
f.close()
with open(r'C:\Users\vainuer\Desktop\Test\test1.txt', 'rb') as f:
    data = pickle.loads(f.read())
    print(data)

# 9、json模块也可以进行序列化，一般用来序列化字典数据
#     1.主要参数：
#     1）obj：将obj对象格式化并存储到文件对象中，文件必须为可写的文件句柄，json只产生str对象，不支持bytes对象。
#     2）skipkey：如果为True，对象的基本类型必须是str，int，float，bool，Non
#     3）ensure_ascii = True:如果为true则所以传入的非ASCII字符都被转义，如果为False则字符将被原样输出。
#     4）check_circular=True:如果为true容器类型的循环引用检查将被跳过
#     5）indent=None:表述数组元素和对象将被按指定的值缩进，可以是整数或字符串’\t’
#     6）sort_keys=False:如果为True字典的输出将按键排序
#     2.json与pickle模块的区别：
#     1)json只能处理基本数据类型。
#       pickle能处理所有的Python的数据类型。
#     2)json用于各种语言之间的字符转换。
#       pickle用于python程序对象的持久化或者python程序对象的持久化或者python程序对象网络传输。
dict_file = {'age': 12, 'job': 'student'}
with open(r'C:\Users\vainuer\Desktop\Test\abc.json', 'w', encoding='utf-8') as f:
    json.dump(dict_file, f)

with open(r'C:\Users\vainuer\Desktop\Test\abc.json', 'r', encoding='utf-8') as f:
    print(json.load(f))

# 1.辨识操作系统：os.name
print(os.name)  # 如果是posix，说明系统是Linux、Unix或Mac OS X，如果是nt，就是Windows系统
# 2.环境变量:os.environ
# print(os.environ)
# 3.环境变量中某个特定数据:os.environ.get('key')
# print(os.environ.get('path'))
# 4.辨识目录权限
print(os.access('new_dir', os.F_OK))  # 查看目录是否存在
# os.F_OK : 是否存在
# os.R_OK : 是否可读
# os.W_OK : 是否可写
# os.X_OK : 是否可执行
# 5.查看当前目录
print(os.getcwd())
# 6.更改当前目录:程序当次运行中有效
os.chdir(r"C:\Users\vainuer\Desktop")
print(os.getcwd())
# 7.创建单级目录：目录若已存在会报异常
if not os.access('new_dir', os.F_OK):
    os.mkdir('new_dir')
# 8.递归创建无限级目录：exist_ok为False若目录存在会报异常 默认False 建议True
os.makedirs('mydir/sub1/sub2/sub3', exist_ok=True)
# 9.删除空目录
os.rmdir('new_dir')
# 10.递归删除路径上的所有空目录
os.removedirs('mydir/sub1/sub2/sub3')
# 11.创建文件
# os.open('1.txt', os.O_CREAT)
# 为了防止资源泄露：创建后关闭对文件的连接
# os.close(os.open('1.txt', os.O_CREAT))
# 12.删除文件 只能删除文件 否则异常
# os.remove('1.txt')
# 13.重命名文件或目录
# os.rename('1.txt', '2.txt')
# 14.重命名文件或目录，可以带全路径一起修正，可以自动递归创建新目录
# os.renames('2.txt', 'aaa/3.txt')
# 15.显示当前目录下所有的子文件及子目录
print(os.listdir("."))
# 16显示当前目录中的所有内容（深度遍历）
for root, subs, files in os.walk(".", True):
    print('当前目录', root)
    print('子目录：')
    for i in subs:
        print(root + '\\' + i)
    print('子文件：')
    for i in files:
        print(root + '\\' + i)

# os.path模块处理,四大职责：
# 1.格式化文件或目录路径
# 2.文件属性获取
# 3.辨识路径（存在or不存在、绝对or相对、目录or文件等）
# 4.解读路径
# 1.格式化文件或目录路径
# 获取绝对路径
print(os.path.abspath("."))
# 返回一个路径的当前目录或文件名
print(os.path.basename(r"aaa\2.txt"))
# 返回一个路径的父目录
print(os.path.dirname(r"aaa\2.txt"))
# os.path.join(path1[, path2[, …]]) 把目录和文件名合成一个路径
print(os.path.join('c:\\', 'aaa', '1.txt'))
# 规范path字符串形式
print(os.path.normpath(r"./aaa\bbb/ccc\1.txt"))

# 2.文件属性获取
# 得到得到文件的大小
print(os.path.getsize('1.txt'))
# 返回最近访问时间
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(os.path.getatime("."))))
# 返回最近文件修改时间
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(os.path.getmtime("."))))
# 返回文件 path 创建时间
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(os.path.getctime("."))))

# 3.辨识路径（存在or不存在、绝对or相对、目录or文件等）
# 判断路径是否存在
print(os.path.exists(r".\5.py"))
# 判断是否为绝对路径
print(os.path.isabs("."))
# 判断路径是否为文件
print(os.path.isfile("."))
# 判断路径是否为目录
print(os.path.isdir("."))

# 4.拆分路径:获得的是元组
# 路径拆分为两部分，后一部分总是最后级别的目录或文件名
print(os.path.split(r"aaa\bbb\2.txt"))
# 路径拆分为两部分，后一部分总是文件的后缀名
print(os.path.splitext(r"aaa\bbb\2.mp4"))
